package com.ruoyi.project.monitor.syslog;

import com.ruoyi.common.annotation.SysLog;
import com.ruoyi.common.enums.BaseStatusEnum;
import com.ruoyi.common.enums.BusinessTypeEnum;
import com.ruoyi.framework.utils.ServletUtils;
import com.ruoyi.project.monitor.entity.SysLoginLog;
import com.ruoyi.project.monitor.entity.SysOperLog;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.common.error.MicaErrorEvent;
import net.dreamlu.mica.core.spring.SpringContextUtil;
import net.dreamlu.mica.core.utils.$;
import net.dreamlu.mica.core.utils.DateUtil;
import net.dreamlu.mica.core.utils.WebUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 系统日志工具类
 *
 * @author dy
 */
@Slf4j
public class SysLogUtils {

    private static SysLogUtils me = new SysLogUtils();

    public static SysLogUtils me() {
        return me;
    }

    /**
     * 记录登陆退出日志
     */
    public void recordLoginLog(SysLoginLog sysLoginLog) {
        if (SpringContextUtil.getContext() != null) {
            SpringContextUtil.getContext().publishEvent(sysLoginLog);
        }
    }

    /**
     * 适用于网络请求
     */
    public void recordOperLog(final JoinPoint point, Object jsonResult, SysOperLog sysOperLog) {
        // 获得注解
        SysLog sysLog = getAnnotationLog(point);
        if (sysLog == null) {
            return;
        }

        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();

        HttpServletRequest request = WebUtil.getRequest();
        String requestUrl = request.getRequestURL().toString();
        String requestMethod = request.getMethod();

        // 设置action动作
        sysOperLog.setBusinessType(sysLog.businessType().ordinal());
        sysOperLog.setStatus(BaseStatusEnum.DB_STATUS_SUCCESS.getStatus());
        // 设置标题
        sysOperLog.setTitle(sysLog.title());
        String ip = WebUtil.getIP();
        sysOperLog.setMethod($.format("{}.{}()", strClassName, strMethodName));
        sysOperLog.setRequestMethod(requestMethod);
        sysOperLog.setOperUrl(requestUrl);
        sysOperLog.setOperIp(ip);
        sysOperLog.setOperTime(new Date());
        sysOperLog.setOperParam(ServletUtils.getRequestBody(point));
        sysOperLog.setJsonResult($.toJson(jsonResult));

        if (SpringContextUtil.getContext() != null) {
            SpringContextUtil.getContext().publishEvent(sysOperLog);
        }
    }

    /**
     * micaError转换
     */
    public SysOperLog turnErrorToOper(MicaErrorEvent event) {
        try {

            SysOperLog operLog = new SysOperLog();
            operLog.setTitle($.format("{}-{}", event.getFileName(), event.getLineNumber()));
            operLog.setOperName($.format("{}-{}", event.getAppName(), event.getEnv()));
            operLog.setBusinessType(BusinessTypeEnum.ERROR.getDictValue());
            operLog.setStatus(BaseStatusEnum.DB_STATUS_FAIL.getStatus());
            operLog.setJsonResult(event.getStackTrace());
            operLog.setErrorMsg(event.getMessage());
            // 设置方法名称
            operLog.setRequestMethod(event.getRequestMethod());
            operLog.setMethod($.format("{}.{}()", event.getClassName(), event.getMethodName()));
            operLog.setOperTime(DateUtil.toDate(event.getCreatedAt()));
            // 请求的地址，系统内部错误不计入IP访问
            operLog.setOperIp("127.0.0.1");
            operLog.setOperLocation("内网IP");
            operLog.setOperUrl(event.getRequestUrl());

            return operLog;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * 是否存在注解，如果存在就获取
     */
    private SysLog getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(SysLog.class);
        }
        return null;
    }
}
